package com.xxh.securitydemo.config;

import com.xxh.securitydemo.compoent.*;
import com.xxh.securitydemo.dao.UmsResourceDao;
import com.xxh.securitydemo.filter.JwtAuthencationFilter;
import com.xxh.securitydemo.model.UmsResource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsUtils;

import javax.annotation.Resource;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {



    //注入操作资源表的接口
    @Resource
    UmsResourceDao umsResourceDao;


    @Autowired
    CuLoginSuccessHandler cuLoginSuccessHandler;

    @Autowired
    CuLoginFailHandler cuLoginFailHandler;

    @Autowired
    NotLoginHandler notLoginHandler;

    @Autowired
    JwtAuthencationFilter jwtAuthencationFilter;

    @Autowired
    MyAccessDenyHandler myAccessDenyHandler;

    //配置userDetailService和密码加密方式
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailService())
                .passwordEncoder(new BCryptPasswordEncoder());
    }

    //自定义userDetailService（）
    @Bean
    AdminUserDetailService userDetailService() {
        return new AdminUserDetailService();
    }

    //关键配置
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //第1步：解决跨域问题。cors 预检请求放行,让Spring security 放行所有preflight request（cors 预检请求）
        http.authorizeRequests().requestMatchers(CorsUtils::isPreFlightRequest).permitAll();

        //第2步：让Security永远不会创建HttpSession，它不会使用HttpSession来获取SecurityContext
        http.csrf().disable()
//                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                .headers().cacheControl();

        //放行登录请求
        http.authorizeRequests()
                .antMatchers("/login/**", "/", "/cap").permitAll()
                //测试认证接口
                .antMatchers("/bz1").authenticated();


        //自定义登录接口,失败、成功处理界面
        http.formLogin().loginProcessingUrl("/login").successHandler(cuLoginSuccessHandler).failureHandler(cuLoginFailHandler);

        //jwt拦截器置于用户名密码拦截器之前
        http.addFilterBefore(jwtAuthencationFilter, UsernamePasswordAuthenticationFilter.class);

        //自定义异常事件
        //AuthenticationEntryPoint 用来解决匿名用户访问无权限资源时的异常
        //AccessDenyHandler 用来解决认证过的用户访问无权限资源时的异常
        http.exceptionHandling()
                .authenticationEntryPoint(notLoginHandler)
                .accessDeniedHandler(myAccessDenyHandler);

    }


    //加载访问URL所需资源，注释掉该bean可以移除URL鉴权
//    @Bean
    DynamicSecurityService dynamicSecurityService(){
        return () -> {
            List<UmsResource> umsResources = umsResourceDao.selectList(null);
            ConcurrentHashMap<String, ConfigAttribute> map = new ConcurrentHashMap<>();
            for (UmsResource u:umsResources){
                map.put(u.getUrl(), new SecurityConfig(u.getId()+":"+u.getName()));
            }
            return map;
        };
    }


    @Override
    public void configure(WebSecurity web) throws Exception {
        //将项目中静态资源路径开放出来
        web.ignoring().antMatchers(
                "/config/**", "/css/**",
                "/fonts/**", "/img/**", "/js/**", "/images/**",
                "/static/**",
                "/v2/api-docs",
                "/swagger-resources/configuration/ui",
                "/swagger-resources",
                "/swagger-resources/configuration/security",
                "/swagger-ui.html",
                "/webjars/**");
    }

}
